SlackワークフローによるメッセージログをAPI経由で処理した時に気をつけているポイント
Slackのログを加工して利用する際の手段として、個人的にGASを利用しています。取得したデータを一時出力する際にSpreadSheetが便利なためです。
ログの構成自体は公式ドキュメントを見るとシンプルに見えます。ただし、これがワークフローによる出力やアプリからのカスタムステップになると変わってきます。
今回はワークフローからポストされた内容をGASでAPI経由にて取り扱う際の注意事項について挙げます。
API経由でログを取得する準備
Slack Appを作成し、conversations.history API経由でログを取得します。
GASで取得する場合は以下のようなコードを実行します。
var apiUrl = "https://slack.com/api/conversations.history?" +
"channel=" + SLACK_CHANNEL +
"&oldest=" + START_TIME_STAMP +
"&latest=" + END_TIME_STAMP;
const options = {"headers": { 'Authorization': 'Bearer ' + SLACK_TOKEN }};
var response = UrlFetchApp.fetch(apiUrl, options);
var responseData = JSON.parse(response);
SLACK_CHANNELはチャンネル名ではなくURLに含まれるユニークIDを、SLACK_TOKENはxoxp-
から始まるものを利用します。
実際のログを解析する
APIドキュメントにあるCommon successful responseを見るとわかりますが、投稿メッセージを取得したいのであればmessages
以下からテキストを取るだけです。ですが、ワークフローの場合は幾つか独自仕様が追加されます。
以下、ワークフロー経由でポストされたメッセージの一部です。
これをAPIでログとして取得すると以下のようになります。
{
reply_users_count=2.0,
username=問い合わせ,
bot_id=XXXXXXXXXX,
reply_count=2.0,
app_id=XXXXXXXXXXXX,
thread_ts=1728431546.929719,
subscribed=false,
blocks=[
{
elements=[
{
type=rich_text_section,
elements=[
{
type=text,
style=
{
bold=true
},
text=問い合わせフォーム
},
{
type=text,
text= submission from
},
{
user_id=XXXXXXXXXX,
type=user
},
{
text=,
type=text
},
{
type=text,
text=総合受付FAQで類似した問い合わせがないことを確認しましたか?,
style=
{
bold=true
}
},
{
type=text,
text=
},
{
text=はい,
type=text
},
{
type=text,
text=※「いいえ」となっている場合はサービス開発室で
},
{
type=link,
text=総合受付FAQ,
url=https://www.notion.so/
},
{
text=を確認してください。,
type=text
},
{
style=
{
bold=true
},
type=text,
text=種類 ※質問対象を選択してください。不明な場合は「全般」にて。提案・要望はBackLogへ。Zendeskは #help-zendeskへ。
},
{
text=,
type=text
},
{
type=text,
text=CMP
},
{
text=,
type=text
},
{
text=問い合わせ元(お客様経由であればお客様名を、社内が発端であれば 社内 と記入),
style=
{
bold=true
},
type=text
},
{
type=text,
text=
},
{
text=XXX,
type=text
},
{
type=text,
text=
},
{
text=件名(○○を知りたい、等簡潔に,
style=
{
bold=true
},
type=text
},
{
type=text,
text=
},
{
type=text,
text=設定について知りたい
},
{
type=text,
text=詳細は以下スレッドに続きます
}
]
}
],
type=rich_text,
block_id=+xxx
}
],
is_locked=false,
type=message,
subtype=bot_message,
reply_users=[XXXXXX],
latest_reply=1728437335.615259,
ts=1728431546.929719,
text=*問い合わせフォーム* submission from <@XXXXXXXX>
*総合受付FAQで類似した問い合わせがないことを確認しましたか?*
はい
※「いいえ」となっている場合はサービス開発室で<https://www.notion.so/>を確認してください。
*種類 ※質問対象を選択してください。不明な場合は「全般」にて。提案・要望はBackLogへ。Zendeskは #help-zendeskへ。*
CMP
*問い合わせ元(お客様経由であればお客様名を、社内が発端であれば 社内 と記入)*
XXX
*件名(○○を知りたい、等簡潔に*
設定について知りたい
詳細は以下スレッドに続きます}
ワークフロー経由で投稿された後にワークフローを改修して投稿しても、投稿元のbot_idなどは変わりません。つまり、アップデートした時刻がわかるのならthread_ts
にて、そうでなければelements
の配列長、及びtext
の中身で個別判定する必要がでてきます。一度ワークフローを組み立てて公開すると、順番を変え辛いとも言えます。
そしてもう一つ気をつけるべきことは、ワークフロー内にリンクテキストが存在する場合。link
ブロックが途中に挟まる形となるため、type=text
だけ判定して取得した場合は欠け落ちることになります。
ログから効率よくピックアップする
実際に使っている方法として、一例ですが以下のような手続きとなります。
function makeTitle(data) {
var is_title = false
var is_finish = false;
var _title = ""
var _length = data.elements.length
var count = 0
data.elements.map(function (cell) {
count += 1
var cell_text = ""
if (cell.type == "text") {
cell_text = cell.text.slice(0).replace(/[\r\n]+/g,"")
}
if (cell.type == "text" && cell_text == "件名(○○を知りたい、等簡潔に" && cell.style.bold == true) {
is_title = true
return;
}
if (count == _length) {
is_finish = true
return;
}
if (is_title == false) return;
if (is_finish == true) return;
if (cell.type == "text") { _title = _title + cell_text }
if (cell.type == "link") { _title = _title + cell.url}
});
return _title;
}
ネックは、項目のテキストを変更した場合には都度修正が必要になるところです。
あとがき
ワークフロー経由での投稿ログを元に処理している業務が幾つかありますが、想定していないデータが入力されることで正常に取得できないことも時折あります。一応都度ログをダンプして確認できるようにはしていますが、たまにデータに対して想定していないAPIの動作が行われることもあり、頭を抱える要素の一つだったりします。
「項目の順番を変えてくれ」という相談が来ることによって渋い顔になる場合は、こういった諸事情で中々判定が辛いと説明できるとよいかもしれません。